#!/bin/sh

ME=$0
SCRIPT_DIR="$1/Contents/Resources"
TARGET_DIR="$3"

#load vars
. "${SCRIPT_DIR}/USERDATA"


check_os()
{
	LEOPARD=1
	TIGER=1

	HOST_SW_VERS=`/usr/bin/defaults read "/System/Library/CoreServices/SystemVersion" ProductVersion`
	if ( echo $HOST_SW_VERS | grep "^10.5">/dev/null ); then
		HOST_LEOPARD=0
		HOST_TIGER=1
	elif ( echo $HOST_SW_VERS | grep "^10.4">/dev/null ); then
		HOST_TIGER=0
		HOST_LEOPARD=1
	else
		echo "OS $HOST_SW_VERS not supported"
		exit 3
	fi
	
	TARGET_SW_VERS=`/usr/bin/defaults read "${TARGET_DIR}/System/Library/CoreServices/SystemVersion" ProductVersion`
	if ( echo $TARGET_SW_VERS | grep "^10.5">/dev/null ); then
		LEOPARD=0
		TIGER=1
	elif ( echo $TARGET_SW_VERS | grep "^10.4">/dev/null ); then
		LEOPARD=1
		TIGER=0
	else
		echo "OS $TARGET_SW_VERS not supported"
		exit 3
	fi
	
	if [ $HOST_LEOPARD -ne $LEOPARD ] || [ $HOST_TIGER -ne $TIGER ]; then
		echo "Host version ($HOST_SW_VERS) is not the same as the target ($TARGET_SW_VERS)"
		exit 3
	fi

	# setup commands and switches based on OS, we have to separate out some 
	# parameters to make sure DB locations are quoted properly
	if [ $LEOPARD -eq 0 ]; then
		DSLocalDB="${TARGET_DIR}/var/db/dslocal/nodes/Default"
	
		if [ ! -e "$DSLocalDB" ]; then
			echo "Can't find target ${DSLocalDB}"
			exit 2
		fi
		
		serviceCmd="/usr/bin/dscl"
		prefix='-f'
		dsNode=${DSLocalDB}
		suffix="localonly"
		groupkey="GroupMembership"
	
		uidKey="UniqueID"
		databasePath="/Local/Target/"
		userRoot="${databasePath}Users"
		userPath="${userRoot}/${shortname}"
		adminPath="${databasePath}Groups/admin"
	
	elif [ $TIGER -eq 0 ]; then
	
		NetInfoDB="${TARGET_DIR}/var/db/netinfo/local.nidb";
	
		if [ ! -e "${NetInfoDB}" ]; then
			echo "Can't find target ${DSLocalDB}"
			exit 2
		fi
	
		serviceCmd="/usr/bin/nicl"
		prefix='-raw'
		dsNode=${NetInfoDB}
		suffix=""
		databasePath="/";
		groupkey="users"
		if [ ${#genUID} -ne 36 ]; then
			genUID=`/usr/bin/uuidgen`
		fi
	
		uidKey="uid"
		userRoot="${databasePath}users"
		userPath="${userRoot}/${shortname}"
		adminPath="${databasePath}groups/admin"
	
	else
		echo "OS not supported"
		exit 3
	fi

}

check_uid()
{
	if [ ${#uid} -eq 0 ]; then
		#search for unused uid after 500
		for ((uid=501; uid<600; uid++)); do
			output=`$serviceCmd $prefix "$dsNode" $suffix -search $userRoot $uidKey $uid`
			if [ "$output" == "" ]; then
				break
			fi
		done
	fi 
	
	#make sure uid is only digits. We probably ought to test for valid uid ranges too. for now just 100+
	if [ ! `echo $uid | grep -E "^[1-9][0-9]{2,9}$"` ] ; then
		echo "Bad UID $uid"
		exit 1
	fi
}

check_shortname()
{
	#we're being extra safe here. shortname must be 1 to 31 alphanumeric characters (first is alpha).
	if ! echo $shortname | grep -E "^[a-zA-Z_][a-zA-Z0-9_]{0,30}$">/dev/null ; then
		echo "Bad shortname ${shortname:-(empty)}"
		echo "Short name should only be lowercase letters or numbers (max 31 for simplicity)"
		exit 1
	fi
	
	SHORTNAME=`echo $shortname | tr "[:lower:]" "[:upper:]"`
}

check_password()
{
	#check for password_hash file
	if [ -f "${SCRIPT_DIR}/password_hash" ]; then
		password_hash=`cat "${SCRIPT_DIR}/password_hash"`
	fi

	if [ ${#password_hash} -ne 1240 ]; then
		if [ ${#password} -lt 1 ]; then
			echo "Invalid password"
			exit 1
		else 
			#generate password hash
			password_hash=`"${SCRIPT_DIR}/shadowHash" $password`
		fi
	fi
}

check_longname()
{
	#use shortname for longname if we didn't specify
	if [ ${#longname} -eq 0 ]; then
		longname=$shortname
	fi
}

check_gid()
{
	if [ ${#gid} -eq 0 ]; then
		gid=20
	fi

	#make sure gid is only digits. 
	if [ ! `echo $gid | grep -E "^[0-9]+$"` ] ; then
		echo "Bad GID $gid"
		exit 1
	fi
}

check_pic()
{
	if [ ${#pic} -eq 0 ]; then
		pic="/Library/User Pictures/Nature/Zen.tif"
	fi
}

check_shell()
{
	if [ ${#shell} -eq 0 ]; then
		shell="/bin/bash"
	fi
}

check_home()
{
	if [ ${#user_home} -eq 0 ]; then
		user_home="/Users/%u"
	fi
	
	#substitute placeholders
	user_home=`echo $user_home | sed -e "s/%u/${shortname}/" -e "s/%n/$uid/" -e "s/%l/${shortname:0:1}/" -e "s/%L/${SHORTNAME:0:1}/"`
}

check_os
check_shortname
check_password
check_uid 
check_gid
check_pic
check_shell
check_home

echo "Creating new user $shortname using: $serviceCmd $prefix $dsNode $suffix"
#these are the commands needed to create a base user. it will bail out if the first command fails
$serviceCmd $prefix "$dsNode" $suffix -create $userPath || exit 1
$serviceCmd $prefix "$dsNode" $suffix -create $userPath realname "${longname}"
$serviceCmd $prefix "$dsNode" $suffix -create $userPath gid ${gid}
$serviceCmd $prefix "$dsNode" $suffix -create $userPath $uidKey ${uid}
$serviceCmd $prefix "$dsNode" $suffix -create $userPath home "${user_home}"
$serviceCmd $prefix "$dsNode" $suffix -merge $userPath authentication_authority ";ShadowHash;"
$serviceCmd $prefix "$dsNode" $suffix -create $userPath picture "${pic}"
$serviceCmd $prefix "$dsNode" $suffix -create $userPath passwd "*"
$serviceCmd $prefix "$dsNode" $suffix -create $userPath shell "${shell}"

# lookup/save generated uid
if [ ${#genUID} -eq 36 ]; then
	#save guid if we specified one
	$serviceCmd $prefix "$dsNode" $suffix -create $userPath generateduid ${genUID}
else 
	#otherwise get the auto generated one 
	genUID=`$serviceCmd $prefix "$dsNode" $suffix -read ${userPath} generateduid|awk '{print $2}'`
fi

#create shadow hash folder if necessary and set perms
if [ ! -d "${TARGET_DIR}/var/db/shadow/hash" ]; then
	/bin/mkdir -p "${TARGET_DIR}/var/db/shadow/hash"
	/usr/sbin/chown -R 0:0 "${TARGET_DIR}/var/db/shadow"
	/bin/chmod 700 "${TARGET_DIR}/var/db/shadow"
fi 

#create shadow hash file and set perms
echo "$password_hash">"${TARGET_DIR}/var/db/shadow/hash/$genUID"
/bin/chmod 600 "${TARGET_DIR}/var/db/shadow/hash/$genUID"

#if admin flag is set, then add user to admin group
if [ $admin -eq 1 ]; then
	$serviceCmd $prefix "$dsNode" $suffix -merge $adminPath $groupkey "${shortname}"
fi

if [ $hide_user -eq 1 ]; then
	/usr/bin/defaults write "${TARGET_DIR}/Library/Preferences/com.apple.loginwindow" HiddenUsersList -array $shortname
fi

exit 0
